package com.guiji.text2video.fastvideo.service.Impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.guiji.text2video.common.core.constant.TTSContants;
import com.guiji.text2video.fastvideo.domain.vo.TTSRequest;
import com.guiji.text2video.fastvideo.domain.vo.TTSRequestWeiRuan;
import com.guiji.text2video.fastvideo.domain.vo.Text2videoJob;
import com.guiji.text2video.fastvideo.domain.vo.Text2videoTtsTask;
import com.guiji.text2video.fastvideo.mapper.TextPackageTaskMapper;
import com.guiji.text2video.fastvideo.service.IAsyncTTSService;
import com.guiji.text2video.fastvideo.service.IText2videoJobService;
import com.guiji.text2video.fastvideo.service.IText2videoTtsTaskService;
import com.guiji.text2video.fastvideo.utils.Enums;
import com.guiji.text2video.fastvideo.utils.GeneratID;
import com.guiji.text2video.fastvideo.utils.WavUtils;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Copyright (C), 2018-2021
 * FileName: AsyncAbstractTTSService
 * Author:   scl
 * Date:     2021/7/20 11:21
 * Description: 抽象类用于提取公共方法
 */
public abstract class AsyncAbstractTTSService implements IAsyncTTSService {
    private static final Logger logger = LoggerFactory.getLogger(AsyncAbstractTTSService.class);
    /**
     * TTS需要去掉的特殊字符
     */
    private static final String TTS_SYMBOL = "[\r\n`^*()|{}''\\[\\]<>~……*（）|{}【】‘”“’]";

    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");

    @Autowired
    private IText2videoJobService text2videoJobService;

    @Value("${file-cache.wav-dir}")
    private String wavDir;

    @Value("${file-cache.wav-url}")
    private String wavUrl;

    @Autowired
    private IText2videoTtsTaskService ttsService;

    private String sginSplit = "WWW";

    @Override
    public void executeTTSAsync(String text, Text2videoJob job, String ttsUrl) {
        commonTTS(text, job, 0, ttsUrl);
    }

    private void commonTTS(String text, Text2videoJob job, int temp, String url) {

        String newText = text.replaceAll(TTS_SYMBOL, "");
        String wavPath = job.getJobId() + "/" + UUID.randomUUID().toString().toLowerCase() + ".wav";


        Request request = null;

        //如果是微软TTS,解析语气参数,语速放慢100倍。
        if (url.contains("381")) {
            TTSRequestWeiRuan ttsRequestWeiRuan = new TTSRequestWeiRuan();
            ttsRequestWeiRuan.setText(newText);
            ttsRequestWeiRuan.setSpeech_rate(job.getTtsRate());
            String speaker = job.getTtsSpeaker();
            ttsRequestWeiRuan.setSpeaker(speaker.split(sginSplit)[0]);
            String yuqi = speaker.split(sginSplit)[1];
            if (speaker.split(sginSplit).length == 3) {
                String pitch = speaker.split(sginSplit)[2];
                ttsRequestWeiRuan.setPitch(Double.parseDouble(pitch));
            } else {
                ttsRequestWeiRuan.setPitch(1.00);
            }
            String value = "{\"ActionArgs\":{\"381\":{\"startTag\":\"<mstts:express-as style=\\\"" + yuqi + "\\\">\",\"endTag\":\"</mstts:express-as>\",\"cut_slience_mode\": \"1\"}}}";
            RequestBody body = RequestBody.create(MEDIA_TYPE, JSON.toJSONString(ttsRequestWeiRuan));
            request = new Request.Builder().addHeader("handshark", value).post(body).url(url).build();
        } else {
            TTSRequest ttsRequest = new TTSRequest();
            ttsRequest.setText(newText);
            ttsRequest.setSpeaker(job.getTtsSpeaker());
            ttsRequest.setSpeech_rate(job.getTtsRate());
            RequestBody body = RequestBody.create(MEDIA_TYPE, JSON.toJSONString(ttsRequest));
            request = new Request.Builder().post(body).url(url).build();
        }
        //快速失败
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.MINUTES)
                .build();
        Response response = null;
        try {
            response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                boolean isW = WavUtils.writeToFile(wavDir + wavPath, response.body().bytes());
                if (!isW) {
                    WavUtils.writeToFile(wavDir + wavPath, response.body().bytes());
                }
            } else {
                insertVideoTts(Enums.JobSign.NLP_FAILED.getKey(), null, text, wavPath, job);
                logger.error("tts error. job_id:{},文本:{},响应body: {} ", job.getJobId(), newText, response.toString());
                return;
            }
        } catch (Exception e) {
            if (e.toString().contains("SocketTimeoutException") && temp != 3) {

                logger.info("因为SocketTimeoutException异常，TTS执行重试:{}", JSON.toJSONString(request));
                temp++;
                commonTTS(text, job, temp, url);
                logger.error("TTS执行重试:{}.retry size:{}", text, temp);
                return;
            } else {
                insertVideoTts(Enums.JobSign.NLP_FAILED.getKey(), null, text, wavPath, job);
                logger.error("tts error {}", e);
                return;
            }

        }

        double dts = WavUtils.calculationDuration(wavDir + wavPath);
        if (dts < 0.001 && temp != 3) {
            //添加重试
            logger.info("TTS执行重试:{},语音长度为:{}",temp,dts);
            temp++;
            commonTTS(text, job, temp, url);
        }else{
            insertVideoTts(Enums.JobSign.SUCCESS.getKey(), Convert.toStr(dts), text, wavPath, job);
        }

    }

    /**
     * @descp: 记录TTS结果，无论错误或者正确
     * @param: String isSuccess,String jobId,String text,String wavPath,Text2videoJob job
     * @Author: scl
     * @Date: 2021/7/20 11:47
     */
    private void insertVideoTts(String isSuccess, String duration, String text, String wavPath, Text2videoJob job) {
        Text2videoTtsTask ttsTask = new Text2videoTtsTask();
        ttsTask.setJobId(job.getJobId());
        ttsTask.setWavText(text);

        if (Enums.JobSign.SUCCESS.getKey().equals(isSuccess)) {
            ttsTask.setWavPath(wavUrl + wavPath);
            ttsTask.setWavDuration(duration);
        } else {
            job.setIsSuccess(Enums.JobSign.TTS_FAILED.getKey());
            text2videoJobService.updateText2videoJob(job);
        }
        ttsTask.setTtsId(GeneratID.getTTSGeneratID());
        ttsTask.setIsSuccess(isSuccess);
        ttsTask.setCreateTime(new Date());
        ttsService.insertText2videoTtsTask(ttsTask);
    }
}